﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Data;
using System.Data.OleDb;
using System.Drawing;
namespace ShpRead
{
    public class Shp
    {
        /* 下面数据成员是Shp文件头对应的分段信息，具体参考设计指导书*/
        byte[] filecode = { 0, 0, 0, 0 };
        byte[] rev1 = { 0, 0, 0, 0 };
        byte[] rev2 = { 0, 0, 0, 0 };
        byte[] rev3 = { 0, 0, 0, 0 };
        byte[] rev4 = { 0, 0, 0, 0 };
        byte[] rev5 = { 0, 0, 0, 0 };
        byte[] filelength = { 0, 0, 0, 0 };
        byte[] filever = { 0, 0, 0, 0 };
        byte[] shpType = { 0, 0, 0, 0 };
        byte[] xmin = { 0, 0, 0, 0, 0, 0, 0, 0 };
        byte[] ymin = { 0, 0, 0, 0, 0, 0, 0, 0 };
        byte[] xmax = { 0, 0, 0, 0, 0, 0, 0, 0 };
        byte[] ymax = { 0, 0, 0, 0, 0, 0, 0, 0 };
        byte[] zmin = { 0, 0, 0, 0, 0, 0, 0, 0 };
        byte[] zmax = { 0, 0, 0, 0, 0, 0, 0, 0 };
        byte[] mmin = { 0, 0, 0, 0, 0, 0, 0, 0 };
        byte[] mmax = { 0, 0, 0, 0, 0, 0, 0, 0 };
        // ----- 以上是Shp文件文件头信息-----// //

        FileStream fs = null;
        BinaryReader bRead = null;
        OleDbDataAdapter myadapter;
        DataSet myds;
        string[] fields;
        public DataSet GetDataSet()
        {
            return myds;
        }
        public string GetFieldValue(int objectID,int index)
        {
            /* 根据给定的objectid和字段名，返回相应的字段值
             * 操作提示： DataTable的Select函数可以通过指定条件查询* 
             */
            DataTable dt = myds.Tables[0];

            return dt.Select()[objectID][index].ToString();//获取字段值
        }
        public int OpenShpFile(string filename)
        {
            /*
            * 通过filename参数打开shp文件，并初始化数据集，以及将文件头信息通过CopyToStru填充到
            * 文件头分段信息中；dbf的链接字符串为：
            * provider=microsoft.jet.oledb.4.0;data source=文件所在目录;Extended Properties=dBASE IV;
            * Select 语句的写法为:  
            *    select * from dbf文件名
            * 由于参数是文件名，因此，需要从文件名中截取出文件所在路径和dbf文件名，此处的
            * dbf文件名为不带路径和扩展名的文件名！！！！  
            * shp文件是二进制格式的文件，因此需用二进制方式读取
            */
            int l;
            if (File.Exists(filename))
            {
                l = 1;
            }
            else
            {
                l = -1;
            }
            fs = File.OpenRead(filename);
            bRead = new BinaryReader(fs);
            //读取前100字节
            byte[] readdata = new byte[100];   
            readdata = bRead.ReadBytes(100);
            this.CopyToStru(readdata);         //执行CopyToStru函数将头文件填充赋值
            
            string pathname = System.IO.Path.GetDirectoryName(filename);  //获取文件目录
            string strfilename = Path.GetFileNameWithoutExtension(filename);  //获取不带路径和扩展名的文件名
            string s = "provider=microsoft.jet.oledb.4.0;data source=" + pathname + ";Extended Properties=dBASE IV";
            OleDbConnection oc = new OleDbConnection();
            oc.ConnectionString = s;
            oc.Open();
            string s1 = "select * from " + strfilename;
            OleDbCommand ocm = new OleDbCommand();
            ocm.Connection = oc;
            ocm.CommandText = s1;
            ocm.CommandType = CommandType.Text;
            ocm.ExecuteNonQuery();
            myadapter = new OleDbDataAdapter(s1,oc);
            myds = new DataSet();
            myadapter.Fill(myds, strfilename);  //初始化数据集
            return l;

        }
        public int  GetNextShp(out int shptype,out object shpContent,out int recordID)
        {
            byte[] recordhead = new byte[4];
            #region 读取多边形shp, shptype = 5;
            if (GetFileType() == 5)//多变形
            {
                /*
                 * 
                 * 此处补充代码，完成点对象的读取
                 * 
                 */
                if (bRead.BaseStream.Position >= bRead.BaseStream.Length)    //如果文件流读取到文件末尾
                {
                    shptype = 0; recordID = 0; shpContent = null;
                    return 0;
                }
                List<PointF> lo = new List<PointF>();  //集合
                LinesShp ls = new LinesShp();
                ls.RecordID = bRead.ReadInt32();
                recordID = ls.RecordID;              //记录头，记录数目号
                int DataLength = bRead.ReadInt32();  //记录头，内容长度
                shptype = bRead.ReadInt32();         //shp类型
                for (int i = 0; i < 4; i++)
                {
                    ls.Box[i] = bRead.ReadDouble();  //坐标范围
                } 
                ls.NumParts = bRead.ReadInt32();     //子面个数
                ls.NumPoints = bRead.ReadInt32();    //坐标点数
                for (int j = 0; j < ls.NumParts; j++)
                {
                    int parts = new int();
                    parts = bRead.ReadInt32();  //parts数组，记录起始位置
                    
                }
                for(int i=0;i<ls.NumPoints;i++)
                {
                    PointShp ps = new PointShp();
                    ps.pf.X = (float)bRead.ReadDouble();    //point数组，记录所有的坐标信息
                    ps.pf.Y = (float)bRead.ReadDouble();
                    lo.Add(ps.pf);
                    
                }
                
                ls.Points = lo.ToArray();
                
                shpContent = ls;
                return 1;
                
            }
            else
            {
                shptype = 0; recordID = 0; shpContent = null;
                return 0;
            }
            #endregion 多边形处理完成
            
        }
        public void CloseShpFile()
        {
            bRead.Close();
            fs.Close();
        }
        public int CopyToStru(byte[] mainHead)   //将文件头的100个字节分别填到相应的属性变量中
        {

            /*
                * 此函数填充Shp的属性成员，将文件头的100个字节分别填到相应的属性变量中
                * 
                */
            if (mainHead.Length != 100)
            {
                return -1;
            }
            int index = 0;
            for (int i = 0; i < 4; i++, index++)
            {
                filecode[i] = mainHead[index];
            }

            //----以下书写你的代码--------//
            for (int i = 0; i < 4; i++, index++)
            {
                rev1[i] = mainHead[index];
            }
            for (int i = 0; i < 4; i++, index++)
            {
                rev2[i] = mainHead[index];
            } 
            for (int i = 0; i < 4; i++, index++)
            {
                rev3[i] = mainHead[index];
            } 
            for (int i = 0; i < 4; i++, index++)
            {
                rev4[i] = mainHead[index];
            } 
            for (int i = 0; i < 4; i++, index++)
            {
                rev5[i] = mainHead[index];
            }
            for (int i = 0; i < 4; i++, index++)
            {
                filelength[i] = mainHead[index];
            }
            for (int i = 0; i < 4; i++, index++)
            {
                filever[i] = mainHead[index];
            }
            for (int i = 0; i < 4; i++, index++)
            {
                shpType[i] = mainHead[index];
            }
            for (int i = 0; i < 8; i++, index++)
            {
                xmin[i] = mainHead[index];
            }
            for (int i = 0; i < 8; i++, index++)
            {
                ymin[i] = mainHead[index];
            }
            for (int i = 0; i < 8; i++, index++)
            {
                xmax[i] = mainHead[index];

            }
            for (int i = 0; i < 8; i++, index++)
            {
                ymax[i] = mainHead[index];
            }
            for (int i = 0; i < 8; i++, index++)
            {
                zmin[i] = mainHead[index];
            }
            for (int i = 0; i < 8; i++, index++)
            {
                zmax[i] = mainHead[index];
            }
            for (int i = 0; i < 8; i++, index++)
            {
                mmin[i] = mainHead[index];
            }
            for (int i = 0; i < 8; i++, index++)
            {
                mmax[i] = mainHead[index];
            }
                return 1;
        }
        public int GetFileCode()
        {
            int kl = 0;
            //  此处补充代码，返回文件代码，若不是9994，请检查你的代码  ---//
            
            Array.Reverse(filecode);
            kl = BitConverter.ToInt32(filecode, 0);
            return kl;
        }
        public int GetFileLength()
        {
            int kl = 0;
            //补充代码----  返回文件长度---////
            Array.Reverse(filelength);
            kl = BitConverter.ToInt32(filelength, 0);
            return kl * 2;// 为什么乘以2  ？？？？指导书中第三页倒数第六行有说明

        }
        public int GetFileVer()
        {
            /*
              * 功能： 返回文件版本 对应filever
              * 补充代码
              */
            int kl;
            kl = BitConverter.ToInt32(filever, 0);
            return kl;
        }
        public int GetFileType()
        {
            int kl = 0;
            //补充代码---  返回类型 对应shpType变量///
            try
            {
                kl = BitConverter.ToInt32(shpType, 0);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
            return kl;
        }
        public double GetXMin()
        {
            //获得边界盒中的x最小值---////
            double kl = 0;
            //代码书写处---///
            kl = BitConverter.ToDouble(xmin, 0);
            return kl; ;

        }
        //------以下函数完整，不需修改---////
        public double GetXMax()//// 获得边界盒中的x最大值--//
        {
            double kl = 0;
            kl = BitConverter.ToDouble(xmax, 0);
            return kl;
        }
        public double GetYMin()// 获得边界盒中的Y最大值--，以下函数类似//
        {
            return BitConverter.ToDouble(ymin,0);
        }
        public double GetYMax()
        {
            return BitConverter.ToDouble(ymax, 0);
        }
        public double GetMMin()
        {
            return BitConverter.ToDouble(mmin, 0);
        }
        public double GetMMax()
        {
            return BitConverter.ToDouble(mmax, 0);
        }
        public double GetZMin()
        {
            return BitConverter.ToDouble(zmin, 0);
        }
        public double GetZMax()
        {
            return BitConverter.ToDouble(zmax, 0);
        }

        //internal object GetYXin()
        //{
        //    throw new NotImplementedException();
        //}
    }
    public class PointShp
    {
        public Int32 RecordID;   
        public PointF pf;
        public string label;
     }
     public class LinesShp
     {
        public Int32 RecordID;
        public double[] Box = new double[4];
        public Int32 NumParts;
        public Int32 NumPoints;
        public Int32[] FirstPointIndexInParts;
        public PointF[] Points;
        public string label;
        
      }

}
